/**
 * ****************************************************************************
 * Project: RoboBridge
 * ----------------------------------------------------------------------------
 * -------------------------- [c]2012 - KrawallMann ---------------------------
 * ---------------------- http://www.krawallmann.de.tc/ -----------------------
 * ****************************************************************************
 * File: AbstractDeviceScanner.java Package:
 * tc.de.krawallmann.robobridge.communication Version: 1.0 Author(s):
 * KrawallMann
 * ****************************************************************************
 * Description:
 * ****************************************************************************
 */
package tc.de.krawallmann.robobridge.communication;

import java.io.IOException;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;

/**
 * The Class AbstractDeviceScanner is a superclass for device scanners.
 * 
 * @param <T>
 *            the generic type
 * @author KrawallMann
 * @version 1.0
 */
public abstract class AbstractDeviceScanner<T extends AbstractRemoteCommunicationDevice> {

	/** The knownDevices. */
	private transient final Map<String, T> knownDevices = new HashMap<String, T>();

	/** The listeners. */
	private transient final Set<DeviceDiscoveryListener<T>> listeners =
			new HashSet<DeviceDiscoveryListener<T>>();

	/**
	 * Adds the communication device.
	 * 
	 * @param device
	 *            the device
	 * @return true, if successful
	 */
	public boolean addCommunicationDevice(final T device) {
		if (!knownDevices.containsKey(device.getAddress())) {
			knownDevices.put(device.getAddress(), device);
			for (final DeviceDiscoveryListener<T> l : listeners) {
				l.onDeviceDiscovered(device);
			}
			return true;
		}
		return false;
	}

	/**
	 * Adds the device discovery listener.
	 * 
	 * @param listener
	 *            the listener
	 * @return true, if successful
	 */
	public boolean addDeviceDiscoveryListener(final DeviceDiscoveryListener<T> listener) {
		return listeners.add(listener);
	}

	/**
	 * Clear communication knownDevices.
	 */
	public void clearCommunicationDevices() {
		knownDevices.clear();
	}

	/**
	 * Close.
	 */
	public abstract void close();

	/**
	 * Contains communication device.
	 * 
	 * @param device
	 *            the device
	 * @return true, if successful
	 */
	public boolean containsCommunicationDevice(final T device) {
		return knownDevices.containsKey(device.getAddress());
	}

	/**
	 * Gets the communication device.
	 * 
	 * @param deviceIP
	 *            the device ip
	 * @return the communication device
	 */
	public T getCommunicationDevice(final String deviceIP) {
		return knownDevices.get(deviceIP);
	}

	/**
	 * Checks if is knowndevice.
	 * 
	 * @param device
	 *            the device
	 * @return true, if is knowndevice
	 */
	public boolean isKnownDevice(final T device) {
		return this.knownDevices.containsKey(device);
	}

	/**
	 * Checks if is scanning.
	 * 
	 * @return true, if is scanning
	 */
	public abstract boolean isScanning();

	/**
	 * Open.
	 * 
	 * @throws IOException
	 *             Signals that an I/O exception has occurred.
	 */
	public abstract void open() throws IOException;

	/**
	 * Removes the device discovery listener.
	 * 
	 * @param listener
	 *            the listener
	 * @return true, if successful
	 */
	public boolean removeDeviceDiscoveryListener(final DeviceDiscoveryListener<T> listener) {
		return listeners.remove(listener);
	}

	/**
	 * Values.
	 * 
	 * @return the collection
	 */
	public Collection<T> values() {
		return this.knownDevices.values();
	}
}
